package handler

import (
	"fmt"
	"lsgfish/server/internal/model"
	"lsgfish/server/internal/service"
	"lsgfish/server/internal/tool"

	"github.com/gin-gonic/gin"
)

// LoginController 登录控制器
type LoginController struct {
	loginService service.LoginService
	redisService tool.RedisService
}

// NewLoginController 创建登录控制器
func NewLoginController() *LoginController {
	return &LoginController{
		loginService: service.NewLoginService(),
		redisService: tool.NewRedisService(),
	}
}

// EmailRequest 账号请求参数结构体
// @Description 用于请求验证码或检查账号的参数结构
// @Schema
type EmailRequest struct {
	// 用户邮箱账号，格式必须是标准邮箱格式
	Email string `json:"email" uri:"email" form:"email" binding:"required,email" msg:"请输入正确的邮箱格式" example:"user@example.com"`
}

// GetVerifyCode 发送验证码
// @Summary 发送验证码
// @Description 发送验证码到用户邮箱
// @Tags 登录认证
// @Accept json
// @Produce json
// @Param account body EmailRequest true "用户邮箱账号"
// @Success 200 {object} tool.Response "验证码发送成功"
// @Failure 400 {object} tool.Response "参数错误"
// @Failure 500 {object} tool.Response "服务器内部错误"
// @Router /login-verify-code [get]
func (l *LoginController) GetVerifyCode(c *gin.Context) {
	var req EmailRequest
	fmt.Printf("req: %+v\n", req)
	if err := c.ShouldBindQuery(&req); err != nil {
		c.Error(err)
		return
	}
	if err := l.loginService.SendRegisterVerifyCode(req.Email); err != nil {
		tool.Err(c, err.Error())
	} else {
		tool.Succ(c, "验证码发送成功")
	}
}

// CheckEmailRepeat 检查账号是否注册，是否重复
// @Summary 检查账号是否已注册
// @Description 检查用户账号是否已注册，是否重复
// @Tags 登录认证
// @Accept json
// @Produce json
// @Param account path string true "用户邮箱账号"
// @Success 200 {object} tool.Response "账号检测通过"
// @Failure 400 {object} tool.Response "参数错误"
// @Failure 500 {object} tool.Response "服务器内部错误"
// @Router /check-account-repeat/:account [get]
func (l *LoginController) CheckEmailRepeat(c *gin.Context) {
	var req EmailRequest
	if err := c.ShouldBindUri(&req); err != nil {
		tool.Err(c, "请求参数无效")
		return
	}

	err := l.loginService.CheckEmailRepeat(req.Email)
	if err != nil {
		tool.Err(c, err.Error())
		return
	}

	tool.Succ(c, "账号检测通过")
}

// RegisterRequest 注册请求参数
// @Description 用户注册时提交的信息结构
// @Schema
type RegisterRequest struct {
	// 用户邮箱账号，用于登录系统
	Account string `json:"account" binding:"required,min=6,max=18" msg:"密码长度必须在6-18位之间" example:"admin"`
	// 用户密码，长度6-18位
	Password string `json:"password" binding:"required,min=6,max=18" msg:"密码长度必须在6-18位之间" example:"Password123"`
	// 邮箱，绑定账号，验证账号
	Email string `json:"email" binding:"required,email" msg:"请输入正确的邮箱格式" example:"user@example.com"`
	// 邀请码，可选
	InviteCode string `json:"inviteCode" example:"INVITE123"` //binding:"required,len=10" msg:"邀请码格式错误"
	// 验证码，必须是6位数字
	VerifyCode string `json:"verifyCode" binding:"required,len=6" msg:"验证码必须是6位" example:"123456"`
	// 用户昵称，最长14个字符
	NickName string `json:"nickName" binding:"required,max=14" msg:"昵称长度必须在14位之间" example:"张三"`
}

// Register 用户注册
// @Summary 用户注册
// @Description 用户注册新账号
// @Tags 登录认证
// @Accept json
// @Produce json
// @Param registerInfo body RegisterRequest true "注册信息"
// @Success 200 {object} tool.Response{data=string} "注册成功，返回token"
// @Failure 400 {object} tool.Response "参数错误"
// @Failure 500 {object} tool.Response "服务器内部错误"
// @Router /register [post]
func (l *LoginController) Register(c *gin.Context) {
	var req RegisterRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.Error(err)
		return
	}
	// TODO: 添加账号的校验规则，只有字母和数字

	// 缓存查询 验证码，并验证
	code, err := tool.RedisServiceTool.GetCode(req.Email, tool.RegisterVerifyCodePrefix)
	if err != nil {
		tool.Err(c, "验证码已过期")
		return
	}
	if code != req.VerifyCode {
		tool.Err(c, "验证码错误")
		return
	} else if err := tool.RedisServiceTool.DeleteCode(req.Email, tool.RegisterVerifyCodePrefix); err != nil {
		tool.Err(c, err.Error())
		return
	}

	// 创建用户对象
	user := model.User{
		Account:  req.Account,
		Password: req.Password,
		NickName: req.NickName,
	}

	// 密码加密
	hashedPassword, err := tool.HashPassword(user.Password)
	if err != nil {
		tool.Err(c, "密码加密失败")
		return
	}
	user.Password = hashedPassword
	token, err := l.loginService.Register(&user)
	if err != nil {
		tool.Err(c, err.Error())
		return
	}

	tool.Succ(c, "注册成功", token)
}

// LoginRequest 登录请求参数
// @Description 用户登录时提交的信息结构
// @Schema
type LoginRequest struct {
	// 用户邮箱账号
	Account string `json:"account" binding:"required,min=6,max=18" msg:"请输入账号格式" example:"user@example.com"`
	// 用户密码，长度6-18位
	Password string `json:"password" binding:"required,min=6,max=18" msg:"密码长度必须在6-18位之间" example:"Password123"`
}

// Login 用户登录
// @Summary 用户登录
// @Description 使用账号密码登录
// @Tags 登录认证
// @Accept json
// @Produce json
// @Param loginInfo body LoginRequest true "登录信息"
// @Success 200 {object} tool.Response{data=string} "登录成功，返回token"
// @Failure 400 {object} tool.Response "参数错误"
// @Failure 500 {object} tool.Response "服务器内部错误"
// @Router /login [post]
func (l *LoginController) Login(c *gin.Context) {
	var req LoginRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.Error(err)
		return
	}

	// TODO: 添加账号的校验规则，只有字母和数字

	// 创建用户对象
	user := &model.User{
		Account:  req.Account,
		Password: req.Password,
	}

	token, err := l.loginService.Login(user)
	if err != nil {
		tool.Err(c, err.Error())
		return
	}

	tool.Succ(c, "登录成功", token)
}

// SendRegisterVerifyCode 发送注册验证码
// @Summary 发送注册验证码
// @Description 发送注册验证码到用户邮箱
// @Tags 登录认证
// @Accept json
// @Produce json
// @Param account body EmailRequest true "用户邮箱账号"
// @Success 200 {object} tool.Response "验证码发送成功"
// @Failure 400 {object} tool.Response "参数错误"
// @Failure 500 {object} tool.Response "服务器内部错误"
// @Router /register-verify-code [get]
func (l *LoginController) SendRegisterVerifyCode(c *gin.Context) {
	var req EmailRequest
	if err := c.ShouldBindQuery(&req); err != nil {
		c.Error(err)
		return
	}
	if err := l.loginService.SendRegisterVerifyCode(req.Email); err != nil {
		tool.Err(c, err.Error())
	} else {
		tool.Succ(c, "验证码发送成功")
	}
}

// VerifyCodeLoginRequest 验证码登录请求参数结构体
// @Description 使用验证码进行登录的请求结构
// @Schema
type VerifyCodeLoginRequest struct {
	// 用户账号，邮箱格式
	Account string `json:"account" binding:"required,email" example:"user@example.com"`
	// 验证码，6位数字
	VerifyCode string `json:"verifyCode" binding:"required,len=6" example:"123456"`
}

// VerifyCodeLogin 验证码登录
// @Summary 验证码登录
// @Description 使用验证码进行登录
// @Tags 登录认证
// @Accept json
// @Produce json
// @Param loginInfo body VerifyCodeLoginRequest true "登录信息"
// @Success 200 {object} tool.Response{data=string} "登录成功，返回token"
// @Failure 400 {object} tool.Response "参数错误"
// @Failure 500 {object} tool.Response "服务器内部错误"
// @Router /verify-code-login [post]
func (l *LoginController) VerifyCodeLogin(c *gin.Context) {
	var req VerifyCodeLoginRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.Error(err)
		return
	}

	// 验证 验证码
	if code, err := tool.RedisServiceTool.GetCode(req.Account, tool.LoginVerifyCodePrefix); err != nil {
		tool.Err(c, err.Error())
		return
	} else if code != req.VerifyCode {
		tool.Err(c, "验证码错误")
		return
	} else if err := tool.RedisServiceTool.DeleteCode(req.Account, tool.LoginVerifyCodePrefix); err != nil {
		tool.Err(c, "删除登录验证码失败")
		return
	}

	token, err := l.loginService.VerifyCodeLogin(model.User{
		Account:    req.Account,
		VerifyCode: req.VerifyCode,
		Ip:         c.ClientIP(),
	})
	if err != nil {
		tool.Err(c, err.Error())
		return
	}
	tool.Succ(c, "登录成功", token)
}

// Logout 用户登出
// @Summary 用户登出
// @Description 用户退出登录
// @Tags 登录认证
// @Accept json
// @Produce json
// @Success 200 {object} tool.Response "登出成功"
// @Failure 400 {object} tool.Response "参数错误"
// @Failure 500 {object} tool.Response "服务器内部错误"
// @Router /logout [post]
func (l *LoginController) Logout(c *gin.Context) {
	token := c.GetHeader("Authorization")
	if token == "" {
		tool.Err(c, "未登录状态")
		return
	}

	// 使用DeleteToken方法删除token
	if err := tool.RedisServiceTool.DeleteToken(token); err != nil {
		tool.Err(c, "登出失败:"+err.Error())
		return
	}

	tool.Succ(c, "登出成功")
}
